#!/usr/local/bin/python2.5

_Copyright = "Copyright @ 2010 Michael P. Reilly. All rights reserved."

_SCM_ID = "$Id: keycustodian.py 80 2010-12-14 02:37:31Z arcege@gmail.com $"

import urllib
from relinfo import ReleaseInfo
from kcapp.app import logging, main
from kcapp.database import *
from kcapp.reqhandler import MainRequestHandler

def retrieve_labels(seed):
    query = SeedLabelMap.all()
    query.filter('seed =', seed)
    accum = [e.label for e in query]
    # unable to sort within the query because using references
    return sorted(accum, key=lambda l: l.name)

class MainPage(MainRequestHandler):
    template_name = 'main'
    def process_request(self):
        if self.user:
            query = OSDBUser.all()
            query.filter('author =', self.user)
            c = query.count()
            if c == 0:
                raise self.Redirect('/user/new')
            elif c > 1:
                return self.multiple_user_error(query)
            del query, c

        self.vars['results'] = []
        query = OSDBSeed.all()
        query.filter('author =', self.user)
        for result in query:
            labels = retrieve_labels(result)
            logging.warn('labels from %s = %s' % (result.name, labels))
            self.vars['results'].append(
                ( urllib.quote_plus(str(result.name)),
                  str(result.name),
                  str(result.type),
                  ','.join(
                    [str(l.name) for l in labels]
                  )
                )
            )
            logging.warn('entry %s' % result.name)

    def multiple_user_error(self, users):
        # send email to admin(s) about multiple DB entries
        mail.send_mail(sender="keycustodian.admin@gmail.com",
            to=",".join(Admin_email_addresses),
            subject="Multiple user error",
            body="""\
Hello Admins,

The is a problem with the database; multiple user entries have been identified
with the same Google User id.
%(info)s
"""
        )
        self.template_name = 'multiple_user_error'

class LabelPage(MainRequestHandler):
    template_name = 'label_view'

    def process_request(self, lname):
        q = OSDBLabels.all()
        q.filter('author =', self.user)
        q.filter('name =', lname)
        if q.count() != 1:
            # duplicate label
            raise self.Redirect('/user/label')
        label = list(q)[0]
        results = self.retrieve_seeds(label)
        self.vars['lname'] = lname
        self.vars['results'] = fullresults = []
        for result in results:
            labels = retrieve_labels(result.seed)
            logging.debug('labels for %s = %s' % (result.seed.name, labels))
            e = (
                urllib.quote_plus(str(result.seed.name)),
                str(result.seed.name),
                str(result.seed.type),
                ','.join(
                  [str(l.name) for l in labels]
                )
            )
            logging.warn("entry = %s" % repr(e))
            fullresults.append( e
            )

    def retrieve_seeds(self, label):
        seeds = []
        q = SeedLabelMap.all()
        q.filter('label =', label)
        seeds = list(q)
        logging.warn('seeds = %s' % repr(seeds))
        return seeds

class LabelAssignPage(MainRequestHandler):
    template_name = None
    def process_request(self):
        lname = str(self.request.get('ilabel'))
        if not lname or lname == '--none--':
            raise self.Redirect('/main')
        inames = self.request.get('iname')
        if isinstance(inames, str) or isinstance(inames, unicode):
            inames = [inames]
        q = OSDBLabels.all()
        q.filter('author =', self.user)
        q.filter('name =', lname)
        c = q.count()
        if c != 1:
            # no or duplicate label
            if c == 0:
                self.send_msg('no label with name %s' % repr(lname), error=True)
            else:
                self.send_msg('more than one label with name %s' % repr(lname), error="True")
            #self.vars['lname'] = lname
            #return
            raise self.Redirect('/user/label')
        label = q.get()
        for name in inames:
            iname = str(name)
            r = OSDBSeed.all()
            r.filter('author =', self.user)
            r.filter('name =', iname)
            c = r.count()
            if c != 1:
                if c == 0:
                    self.send_msg('no seed with name %s' % repr(iname), error=True)
                else:
                    self.send_msg('more than one seed with name %s' % repr(iname), error=True)
                raise self.Redirect('/main')
            seed = r.get()
            logging.info('found seed = %s; label = %s' % (repr(seed.name), repr(label.name)))
            s = SeedLabelMap.all()
            s.filter('seed =', seed)
            s.filter('label =', label)
            c = s.count()
            if c == 0:
                s = SeedLabelMap(seed=seed, label=label)
                s.put()
            elif c > 1:
                self.send_msg('unsupported: more than one label assigned')
            else:
                logging.debug('this label is already assign; s = %s' % results[0])
        raise self.Redirect('/main')

class LabelRemovePage(MainRequestHandler):
    template_name = None
    def process_request(self):
        lname = str(self.request.get('ilabel'))
        inames = self.request.get('iname')
        if isinstance(inames, str) or isinstance(inames, unicode):
            inames = [inames]
        q = OSDBLabels.all()
        q.filter('author = ', self.user)
        q.filter('name =', lname)
        c = q.count()
        if c != 1:
            # no or duplicate label
            if not c:
                self.send_msg('no label with name %s' % repr(lname), error=True)
            else:
                self.send_msg('more than one label with name %s' % repr(lname), error=True)
            raise self.Redirect('/user/label')
        label = q.get()
        for name in inames:
            iname = str(name)
            r = OSDBSeed.all()
            r.filter('author =', self.user)
            r.filter('name =', iname)
            c = q.count()
            if c != 1:
                if not c:
                    self.send_msg('no seed with name %s' % repr(iname), error=True)
                else:
                    self.send_msg('more than one seed with name %s' % repr(iname), error=True)
                raise self.Redirect('/main')
            seed = r.get()
            logging.info('found seed = %s; label = %s' % (repr(seed.name), repr(label.name)))
            s = SeedLabelMap.all()
            s.filter('seed =', seed)
            s.filter('label =', label)
            c = s.count()
            if c < 1:
                self.send_msg('none removed')
            else:
                if c > 1:
                    self.send_msg('unsupported: more than one of the same label assigned')
                for result in s:
                    result.delete()
        raise self.Redirect('/main')

class SearchPage(MainRequestHandler):
    template_name = 'search'
    def process_request(self):
        term = str(self.request.get('term'))
        #if not term:
        #    raise self.Redirect('/main')
        q = OSDBSeed.all()
        q.filter('author =', self.user)
        q.order('name')
        found = []
        self.vars['entries'] = table = []
        for r in q:
            if r.name.find(term) != -1:
                found.append(r)
        for result in found:
            entry = (
                str(result.key()),
                str(result.name),
                str(result.type),
                ','.join(
                    [str(l.name) for l in retrieve_labels(result)]
                )
            )
            table.append(entry)

class DisplayPage(MainRequestHandler):
    template_name = 'display_main'
    multiple_template_name = 'display_select'
    help_url = 'display'
    def process_request(self):
        if self.request.get('submit') == 'Cancel':
            return self.redirect('/main')
        query = OSDBSeed.all()
        query.filter('author =', self.user)
        key = name = None
        try: key = str(self.request.get('key'))
        except SystemError: pass
        try: name = str(self.request.get('name'))
        except SystemError: pass
        if key:
            logging.info('filtering on key %s' % repr(key))
            query.filter('key =', key)
        elif name:
            logging.info('filtering on name %s' % repr(name))
            query.filter('name =', name)
        else:
            logging.error('no value retrieve from CGI')
            return self.no_results()
        if key:
            value = getbykey(key)
            results = [value]
        else:
            results = list(query)
        if len(results) < 1:
            logging.info('no_results()')
            return self.no_results()
        elif len(results) == 1:
            logging.info('single_result(%s)' % results[0])
            return self.single_result(results[0])
        else:
            logging.info('multiple_results(%s)' % results)
            return self.multiple_results(results)

    def no_results(self):
        pass

    def single_result(self, seed):
        self.vars['seed'] = seed

    def multiple_results(self, seeds):
        rows = []
        for seed in seeds:
            logging.info('seed = [%s] (%s, %s, %s)' % (seed.key(), seed.name, seed.url, seed.username))
            rows.append('''\
            <div class="leftcol">
                <input type="radio" name="key" value="%s"/>
            </div>
            <div class="rightcol">
                %s %s %s
            </div>''' % (seed.key(), seed.name, seed.url, seed.username)
            )
        self.vars['tablerows'] = '\n'.join(rows)
        self.template_name = self.multiple_template_name

class EditPage(MainRequestHandler):
    template_name = 'edit_main'
    help_url = 'seed_edit'
    def process_request(self, key):
        seed = getbykey(key)
        self.vars['seed'] = seed
        query = OSDBTypes.all()
        options = []
        for r in query:
            if r.name == seed.type:
                options.append('<option selected="true">%s</option>' % r.name)
            else:
                options.append('<option>%s</option>' % r.name)
        self.vars['typeoptlist'] = '\n'.join(options)
        logging.info('key = %s; seed = %s' % (key, seed))

class EditSubmissionPage(MainRequestHandler):
    template_name = None
    def process_request(self, key):
        submit = str(self.request.get('submit'))
        sname = str(self.request.get('sname'))
        stype = str(self.request.get('stype'))
        surl = str(self.request.get('surl'))
        suname = str(self.request.get('suname'))
        spswd = str(self.request.get('spswd'))
        dirty = False
        if submit == 'Remove':
            raise self.Redirect('/remove/%s' % key)
        elif submit == 'Submit':
            q = OSDBTypes.all()
            q.filter('name =', stype)
            c = q.count()
            if c != 1:
                self.send_msg('invalid type', error=True)
                raise self.Redirect('/display?key=%s' % key)
            entry = getbykey(key)
            if entry is None:
                self.send_msg('could not retrieve entry', error=True)
                raise self.Redirect('/display?key=%s' % key)
            if entry.name != sname:
                entry.name = sname
                dirty = True
            if entry.type != stype:
                entry.type = stype
                dirty = True
            if entry.url != surl:
                entry.url = surl
                dirty = True
            if entry.username != suname:
                entry.username = suname
                dirty = True
            if not entry.password or entry.password.pswd != spswd:
                # delete the old password first
                #if entry.password:
                #    entry.password.delete()
                entry.password.pswd = spswd
                entry.password.put()
                dirty = True
            if dirty:
                entry.put()
        raise self.Redirect('/display?key=%s' % key)

class RemovePage(MainRequestHandler):
    template_name = None
    def process_request(self, key):
        entry = getbykey(key)
        # remove seed/label mappings before removing seed
        query = SeedLabelMap.all()
        query.filter('seed =', entry)
        for e in query:
            e.delete()
        # remove seed
        entry.delete()
        logging.warn('remove (%s, %s)' %
            (entry.author.nickname(), entry.name)
        )
        raise self.Redirect('/main')

class NewMainPage(MainRequestHandler):
    template_name = 'new_main'
    help_url = 'seed_new'
    def process_request(self):
        query = OSDBTypes.all()
        self.vars['typeoptlist'] = [[r.name, r.name == 'Default'] for r in query]

class NewNewMainPage(NewMainPage):
    template_name = 'new'

class NewSubmissionPage(MainRequestHandler):
    template_name = 'new_submission'
    help_url = 'seed_new'
    def process_request(self):
        if self.request.get('submit') == 'Cancel':
            raise self.Redirect('/main')
        self.vars['rname'] = rname = self.request.get('name')
        self.vars['rtype'] = rtype = self.request.get('etype')
        self.vars['rurl'] = rurl  = self.request.get('url')
        self.vars['runame'] = runame= self.request.get('uname')
        self.vars['rpswd'] = rpswd = self.request.get('pswd1')

class NewConfirmPage(MainRequestHandler):
    template_name = None
    def process_request(self):
        rname = self.request.get('name')
        rtype = self.request.get('etype')
        rurl  = self.request.get('url')
        runame= self.request.get('uname')
        rpswd = self.request.get('pswd')

        choice = self.request.get('choice')
        if str(choice).lower() == 'no':
            raise self.Redirect('/main')
        elif str(choice).lower() == 'back':
            return self.go_back(rname, rtype, rurl, runame, rpswd)

        pswd = OSDBPassword(author=self.user, pswd=rpswd)
        pswd.put()

        logging.info('created new password entry: key = %s' % pswd.key())
        record = OSDBSeed(
            author=self.user, name=rname, type=rtype,
            labels=[], url=rurl, username=runame,
            password=pswd
        )
        record.put()
        logging.info('created new seed entry: key = %s' % record.key())
        raise self.Redirect('/main')

    def go_back(self, rname, rtype, rurl, runame, rpswd):
        q = OSDBTypes.all()
        q.order('name')
        options = []
        for t in q:
            options.append( [t.name, t.name == rtype] )
        self.vars['typeoptlist'] = options
        self.vars['name'] = rname
        self.vars['url'] = rurl
        self.vars['uname'] = runame
        self.vars['pswd'] = rpswd
        self.template_name = 'new_main'

class AboutPage(MainRequestHandler):
    help_url = 'about'
    def process_request(self, page):
        if page == 'us':
            self.template_name = 'about_us'
        elif page == 'eula':
            self.template_name = 'eula'
        elif page == 'privacy':
            self.template_name = 'privacy_policy'
        elif page == 'credits':
            self.template_name = 'credits'
        elif page == 'release':
            relinfo = ReleaseInfo()
            self.vars['tag']   = relinfo.tag
            self.vars['revno'] = relinfo.rev
            self.vars['relno'] = relinfo.rel
            self.vars['versid'] = relinfo.versid
            self.template_name = 'release'
        else:
            self.vars['url'] = '/about/%s' % page
            self.template_name = 'badpage'

class BadPage(MainRequestHandler):
    template_name = 'badpage'
    help_url = 'main'
    def process_request(self, urlpart):
        self.vars['url'] = urlpart

URL_Map = [
  ('/main', MainPage),
  ('/display', DisplayPage),
  ('/search', SearchPage),
  ('/edit/submission/(.*)', EditSubmissionPage),
  ('/edit/(.*)', EditPage),
  ('/remove/(.*)', RemovePage),
  ('/new', NewMainPage),
  ('/newnew', NewNewMainPage),
  ('/new/submission', NewSubmissionPage),
  ('/new/confirm', NewConfirmPage),
  ('/label', MainPage),
  ('/label/remove', LabelRemovePage),
  ('/label/assign', LabelAssignPage),
  ('/label/search/(.*)', LabelPage),
  ('/about/(.*)', AboutPage),
  ('/(.*)', BadPage),
]

if __name__ == "__main__":
    main(URL_Map)

